#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
#include "dlm.h"
#include "posixfifo.h"
#include "cJSON.h"

void fx_pool_construct(struct  __dynamic_function_pool* FxPool)
{
	FxPool->nfx = 0;
	FxPool->nmod = 0;
	FxPool->fx = (struct __dynamic_module_function*)malloc(sizeof(struct __dynamic_module_function));
	if(FxPool->fx == NULL)
	{
		fprintf(stderr, "SYS/> {ERROR} Function Array initialize-allocation memory failed.\n" );
		return;
	}
	FxPool->mod = (struct __dynamic_module*)malloc(sizeof(struct __dynamic_module));
	if(FxPool->mod == NULL)
	{
		fprintf(stderr, "SYS/> {ERROR} Module Array initialize-allocation memory failed.\n" );
		return;
	}
	FxPool->_fx = FxPool->fx;
	FxPool->_mod = FxPool->mod;
}

void fx_pool_release(struct  __dynamic_function_pool* FxPool)
{
	int i;
	for(i = 0; i < FxPool->nfx; i++)
	{
		if(FxPool->fx[i].mod_hnd != NULL)
			dlclose(FxPool->fx[i].mod_hnd);
	}

	if(FxPool->fx != NULL)
		free(FxPool->fx);
	FxPool->_fx = NULL;
	
	if(FxPool->mod != NULL)
		free(FxPool->mod);
	FxPool->_mod = NULL;
	FxPool->nfx = 0;
	FxPool->nmod = 0;
}

void fx_pool_list(struct  __dynamic_function_pool* FxPool)
{
	int i;
	for(i = 0; i < FxPool->nfx; i++)
	{
		printf("Module[%d] %s , Execute Entry[%d] %s address: 0x%x\n", 
				FxPool->fx[i].mod_idx, FxPool->fx[i].mod_name,
				FxPool->fx[i].idx, FxPool->fx[i].name, FxPool->fx[i].entry );
	}
}

void load_dynamic_module(char* dynlib_name, struct  __dynamic_function_pool* FxPool)
{
	// 获取当前路径
	char cwd[1024]; getcwd(cwd, 1024);
	// shared library完整路径
	char dynlib_abspath[1024]; sprintf(dynlib_abspath, "%s/%s", cwd, dynlib_name); //printf("%s\n", dynlib_abspath);
	DYNMOD_HND dynlib_hnd = dlopen(/*dynlib_name*/ dynlib_abspath, RTLD_NOW | RTLD_GLOBAL);
	if(dynlib_hnd == NULL)
	{
		fprintf(stderr, "SYS/> {ERROR} load dynamic module '%s' failed.\n", dynlib_name);
		return;
	}
	else
	{
		FIFO_CB fifo;
		fpcb_construct("fxinf.fifo", &fifo);

		char cmd[1024];
		/* 只返回用户自定义的库函数符号(名称), 返回信息写入到dynmod.list文件中
	     * 除去 _init, _fini, _ftext 三个系统函数
	     * nm -A *.so | grep ' T ' | grep -v '_init|_fini|_ftext' | awk '{print $3}'
		 */
		#ifdef OS_Linux
		sprintf(cmd, 
				"nm -A %s | grep ' T ' | grep -v '_init\\|_fini\\|_ftext' | awk '{print $3}' > %s", 
				dynlib_name, fifo.pf);
		#endif
		#ifdef OS_Cygwin
		sprintf(cmd, 
				"nm -A %s | grep ' T ' | grep -v "
				"'"
				"_init\\|_fini\\|_ftext\\| "
				"__gcc_register_frame\\| "
				"__gcc_deregister_frame"
				"'"
				" | awk '{print $3}' > %s", 
				dynlib_name, fifo.pf);
		#endif
		system(cmd);
		fifo.pfread(&fifo);
		fifo.pfarray(&fifo); //fifo.arrprint(&fifo);

		// module数量+1
		FxPool->nmod++;

		int i,f;
		// 本次导入module, 函数全局起始编号
		f = FxPool->nfx + 1;
		strcpy(FxPool->_mod->name, dynlib_name);
		FxPool->_mod->idx = FxPool->nmod;
		// module中第一个函数的全局编号
		FxPool->_mod->fx_idx_start = f; 
				
		for(i = 0; i < fifo.lines; i++/*,f++*/)
		{	
			//函数全局编号
			FxPool->_fx->idx = f;
			//函数符号
			strcpy(FxPool->_fx->name, fifo.arrays[i]);
			/* 获取自定义函数在进程空间中的入口地址 */
			FxPool->_fx->entry = dlsym(dynlib_hnd, FxPool->_fx->name);
			if(FxPool->_fx->entry == NULL)
			{
				#ifdef OS_Linux
				fprintf(stderr, "SYS/> {ERROR} get '%s' entry address failed.\n", FxPool->_fx->name);
				#endif
				#ifdef OS_Cygwin
				//fprintf(stderr, "SYS/> {INFO} '%s' will be ignored.\n", FxPool->_fx->name);
				#endif
				continue;
			}
			//所在module句柄
			FxPool->_fx->mod_hnd = dynlib_hnd;
			//module名称
			strcpy(FxPool->_fx->mod_name, dynlib_name);
			//module全局编号
			FxPool->_fx->mod_idx = FxPool->nmod;
			//fx数量+1
			FxPool->nfx++;
			
			//fx阵列存储空间增加1个单位
			struct __dynamic_module_function* newFx;
			newFx = (struct __dynamic_module_function*)realloc(FxPool->fx, 
					(1 + FxPool->nfx)*sizeof(struct __dynamic_module_function));
			if(newFx != NULL)
			{
				FxPool->fx = newFx;
				//待插入节点入口地址
				FxPool->_fx = &(FxPool->fx[FxPool->nfx]);
			}else{
				fprintf(stderr, "SYS/> {ERROR} fx realloc memory failed!\n");
			}

			//函数全局编号递增+1
			f++;
		}

		// module中最后一个函数的全局编号
		FxPool->_mod->fx_idx_end = f;
		//mod阵列存储空间增加1个单位
		struct __dynamic_module* newMod;
		newMod = (struct __dynamic_module*)realloc(FxPool->mod,
				 (1 + FxPool->nmod)*sizeof(struct __dynamic_module));
		if(newMod != NULL)
		{
			FxPool->mod = newMod;
			FxPool->_mod = &(FxPool->mod[FxPool->nmod]);
		}
		else{
			fprintf(stderr, "SYS/> {ERROR} mod realloc memory failed!\n" );
		}
		//fifo控制体资源释放
		fpcb_release((struct __fifo_pipe_control_block*)&fifo);
	}

}

FUNC_ENTRY fx_get_entry(char* dynlib_name, 
								char* func_name, 
								struct  __dynamic_function_pool* FxPool)
{
	int i, j, k;

	for(i = 0; i < FxPool->nmod; i++)
	{
		if(strcmp(FxPool->mod[i].name, dynlib_name) == 0)
		{
			j = FxPool->mod[i].fx_idx_start;
			k = FxPool->mod[i].fx_idx_end;
			break;
		}
	}

	if(i == FxPool->nmod)
	{
		fprintf(stderr, "FX/> Couldn't found module '%s', No entry for '%s'\n", dynlib_name, func_name);
		return NULL;
	}
	else
	{
		for(i = j-1; i < k; i++)
		{
			if(strcmp(FxPool->fx[i].name, func_name) == 0)
			{
				printf("fx[%d]: '%s' will run.\n", i+1, FxPool->fx[i].name);
				return FxPool->fx[i].entry;
			}
		}
		fprintf(stderr, "FX/> No entry found for '%s'\n", func_name);
		return NULL;
	}
}

int fx_get_idx(char* dynlib_name, 
								char* func_name, 
								struct  __dynamic_function_pool* FxPool)
{
	int i, j, k;

	for(i = 0; i < FxPool->nmod; i++)
	{
		if(strcmp(FxPool->mod[i].name, dynlib_name) == 0)
		{
			j = FxPool->mod[i].fx_idx_start;
			k = FxPool->mod[i].fx_idx_end;
			break;
		}
	}

	if(i == FxPool->nmod)
	{
		fprintf(stderr, "FX/> Couldn't found module '%s', No entry for '%s'\n", dynlib_name, func_name);
		return -1;
	}
	else
	{
		for(i = j-1; i < k; i++)
		{
			if(strcmp(FxPool->fx[i].name, func_name) == 0)
			{
				return FxPool->fx[i].idx;
			}
		}
		fprintf(stderr, "FX/> No entry found for '%s'\n", func_name);
		return -1;
	}
}


void FX_TRIGGER(char* json_cb, char* json_retval, struct  __dynamic_function_pool* FxPool)
{
	//printf("%s\n", json_cb);

	cJSON *cb = cJSON_Parse(json_cb);
	if(cb == NULL)
	{
		printf("FX TRIGGER/> parse control-block stream failed.\n");
		return;
	}

	char* mod = cJSON_GetObjectItem(cb, "mod")->valuestring;
	char* fx = cJSON_GetObjectItem(cb, "fx")->valuestring;
	if(mod == NULL || fx == NULL)
	{
		printf("FX TRIGGER/> 'mod' or 'fx' value is null.\n");
		return;
	}
	// 函数入口地址
	FUNC_ENTRY FX =  fx_get_entry(mod, fx, FxPool);
	if(FX == NULL)
		return;

	/* 返回结果组织成JSON格式字符串 */
	cJSON* FX_retval = cJSON_CreateObject();

	cJSON* argv = cJSON_GetObjectItem(cb, "argv");
	if(FX_retval == NULL || argv == NULL)
	{
		printf("FX TRIGGER/> 'retval' or 'argv' JSON object construct failed.\n");
		return;
	}


	/* 运行函数
	 * 函数传入参数: cJSON* 对象 argv
	 * 函数返回值:  cJSON* 对象 retval
	 */
	((void (*)(cJSON*, cJSON*))FX)((cJSON*)argv, (cJSON*)FX_retval);

	strcpy(json_retval, cJSON_Print(FX_retval)); 
	cJSON_Delete(FX_retval);

	cJSON_Delete(cb);
}